package pl.edu.utp.ga;

import java.util.ArrayList;

import pl.edu.utp.calculations.Range;
import pl.edu.utp.ga.genes.BinaryGene;
import pl.edu.utp.ga.genes.FloatingGene;
import pl.edu.utp.ga.genotypes.BinaryGenotype;
import pl.edu.utp.ga.genotypes.NumberGenotype;
import pl.edu.utp.ga.interfaces.Calculation;
import pl.edu.utp.ga.interfaces.Gene;
import pl.edu.utp.ga.interfaces.Genotype;

public class Individual{
	
	private Population population;
	private Genotype genotype;
	private double rate = Double.POSITIVE_INFINITY;
	
//	public Individual(Population population){
//		this.population = population;
//		genotype = new BinaryGenotype();		
//	}
	
	public Individual(Genotype genotype){
		this.genotype = genotype;
	}
	
	public Individual(Population population, Genotype genotype){
		this.population = population;
		this.genotype = genotype;
	}
	
	public void generate() {
		genotype.generate();
	}
	
	public void generateWithGenesRanges(ArrayList<Range> ranges){
		genotype.setGenesRanges(ranges);
		generate();
	}

	public Population getPopulation() {
		return population;
	}

	public void setPopulation(Population population) {
		this.population = population;
	}

	public void setGenotype(Genotype genotype) {
		this.genotype = genotype;
	}

	public Genotype getGenotype() {
		return genotype;
	}
	
	public double getRate() {
		return rate;
	}
	
	public void rate(Calculation calculation) {
		rate = genotype.rate(calculation);
	}
	
	public ArrayList<Individual> cross(Individual individual){
		ArrayList<Individual> childrens = new ArrayList<Individual>();
		ArrayList<Genotype> genotypes = (ArrayList<Genotype>)genotype.cross(individual.getGenotype().getGenes());
		for(Genotype genotype: genotypes){
			Individual child = new Individual(genotype);
			childrens.add(child);
		}
		return childrens;
	}
	
	public void mutate(){
		genotype.mutate();
	}
	
	public String toString(){
		String text = String.format("Individual: \n" +
									"\tPopulation: %s\n" +
									"\tRate: %.4f\n" +
									"\tGenotype: %s\n",population,rate,genotype);
		if(genotype instanceof BinaryGenotype){
			text = String.format("%s\t[x,y]: %s", text, ((BinaryGenotype)genotype).toDoubleString());
		}
		return text;
	}
	
	public Individual copy(){
		ArrayList<Gene<?>> genes = new ArrayList<Gene<?>>();
		if(genotype instanceof NumberGenotype){
			for(Gene<?> gene: genotype.getGenes()){
				genes.add(new FloatingGene((Double)gene.get()));
			}
			NumberGenotype newGenotype = new NumberGenotype(genes);
			return new Individual(newGenotype);
		} else if(genotype instanceof BinaryGenotype){
			for(Gene<?> gene: genotype.getGenes()){
				genes.add(new BinaryGene((Boolean)gene.get()));
			}
			BinaryGenotype newGenotype = new BinaryGenotype(genes);
			return new Individual(newGenotype);
		}
		return null;
	}
}